package org.class2table.core.table;

import cn.hutool.core.collection.CollectionUtil;
import org.class2table.core.parent.ParentProcessor;
import org.class2table.core.parent.bean.PrimaryKeyInfo;
import org.class2table.core.dictionary.Constants;
import org.class2table.core.table.bean.ColumnMetaData;
import org.class2table.core.table.bean.TableMetaData;
import org.class2table.core.template.SqlTemplate;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class TableProcessor {

    public static TableMetaData getTableMetaData(Connection connection, String dbName, String tableName) throws SQLException {
        Statement statement = connection.createStatement();
        String QUERY_0INFORMATION_SCHEMA0_SQL = String.format(SqlTemplate.Operation.QUERY_0INFORMATION_SCHEMA0_TEMPLATE, dbName, tableName);
        ResultSet resultSetForInformationSchema = statement.executeQuery(QUERY_0INFORMATION_SCHEMA0_SQL);
        List<ColumnMetaData> columnMetaDataList = new ArrayList<>();
        if (resultSetForInformationSchema.next()) {
            do {
                ColumnMetaData columnMetaData = new ColumnMetaData();
                String columnName = resultSetForInformationSchema.getString(1);
                columnMetaData.setColumnName(columnName);
                String columnType = resultSetForInformationSchema.getString(2);
                columnMetaData.setColumnType(columnType);
                String columnDefault = resultSetForInformationSchema.getString(3);
                columnMetaData.setColumnDefault(columnDefault);
                String isNullable = resultSetForInformationSchema.getString(4);
                columnMetaData.setIsNullable(Constants.INFORMATION_SCHEMA.NULL_ABLE.YES.equals(isNullable));
                String dataType = resultSetForInformationSchema.getString(5);
                columnMetaData.setDataType(dataType);
                String columnKey = resultSetForInformationSchema.getString(6);
                columnMetaData.setColumnKey(columnKey);
                String columnComment = resultSetForInformationSchema.getString(7);
                columnMetaData.setColumnComment(columnComment);
                columnMetaDataList.add(columnMetaData);
            } while (resultSetForInformationSchema.next());
        }

        setKeyColumnUsage(columnMetaDataList, statement, dbName, tableName);

        List<PrimaryKeyInfo> primaryKeyInfoList = ParentProcessor.extractPrimaryKeyInfos(columnMetaDataList);

        TableMetaData tableMetaData = null;
        if (CollectionUtil.isNotEmpty(columnMetaDataList)) {
            tableMetaData = new TableMetaData();
            tableMetaData.setTableName(tableName);
            tableMetaData.setEntityAttrMetaDataList(columnMetaDataList);
            tableMetaData.setPrimaryKeyInfoList(primaryKeyInfoList);
        }
        return tableMetaData;
    }

    private static void setKeyColumnUsage(List<ColumnMetaData> columnMetaDataList, Statement statement, String dbName, String tableName) throws SQLException {
        if (CollectionUtil.isEmpty(columnMetaDataList)) {
            return;
        }
        String QUERY_0KEY_COLUMN_USAGE0_FOR_PRIMARY_SQL = String.format(SqlTemplate.Operation.QUERY_0KEY_COLUMN_USAGE0_FOR_PRIMARY_TEMPLATE, dbName, tableName);
        ResultSet resultSetOfKeyColumnUsageForPrimary = statement.executeQuery(QUERY_0KEY_COLUMN_USAGE0_FOR_PRIMARY_SQL);
        List<PrimaryKeyInfo> primaryKeyInfoList = new ArrayList<>();
        if (resultSetOfKeyColumnUsageForPrimary.next()) {
            do {
                PrimaryKeyInfo primaryKeyInfo = new PrimaryKeyInfo();
                int sort = resultSetOfKeyColumnUsageForPrimary.getInt(1);
                primaryKeyInfo.setSort(sort);
                String columnName = resultSetOfKeyColumnUsageForPrimary.getString(2);
                primaryKeyInfo.setColumnName(columnName);
                primaryKeyInfoList.add(primaryKeyInfo);
            } while (resultSetOfKeyColumnUsageForPrimary.next());
        }

        Map<String, Integer> columnNameToSortMap =
                primaryKeyInfoList.stream()
                        .collect(Collectors.toMap(PrimaryKeyInfo::getColumnName, PrimaryKeyInfo::getSort));

        columnMetaDataList.forEach(
                t->{
                    t.setColumnKeySort(columnNameToSortMap.get(t.getColumnName()));
                }
        );
    }

}
